// use error() to print error messages
// (when erlang side gets badarg or, if lucky, {error, Reason})
// use debug() to print verbose messages on ongoing process.
// debug() calls should remain only in debug build

#include <stdarg.h>

// printf to stderr
void error(const char *f, ...)
{
    va_list	ap;
    va_start(ap, f);
    vfprintf(stderr, f, ap);
    fprintf(stderr, "\n");
    va_end(ap);
}

#ifdef DEBUGXXXX
#define debug error
#else
// Is there a trick to make debug() into a macro?
void debug() { }
#endif


#ifndef __FUNCTION__
#define __FUNCTION__ "123"
// XXX checkout what gcc uses
#endif

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define __POS__ __FILE__ ":" TOSTRING(__LINE__)

// in DEBUG AT is equal to 'FILE:LINE: FUNCTION: '
// in RELEASE - just 'FUNCTION: '
#ifdef DEBUG
#define AT __POS__ ": " __FUNCTION__ ": "
#else
#define AT __FUNCTION__ ": "
#endif

#define ZERO(R)                                                     \
{                                                                   \
    int _r = R;                                                     \
    if ( _r )                                                       \
    {                                                               \
        debug(AT "ERROR: " #R " failed with %d", _r);               \
        return _r;                                                  \
    }                                                               \
}

#define ZERO_NOPRINT(R)                                             \
{                                                                   \
    int _r = R;                                                     \
    if ( _r )                                                       \
        return _r;                                                  \
}

#define NONZERO(R)                                                  \
{                                                                   \
    if ( ! (R) )                                                    \
    {                                                               \
        error(AT "ASSERTION FAILED: " #R);                          \
        return -1;                                                  \
    }                                                               \
}

#ifdef DEBUG
#define ASSERT(R)                                                   \
{                                                                   \
    if ( ! (R) )                                                    \
    {                                                               \
        error(AT "ASSERTION FAILED: " #R);                          \
    }                                                               \
}
#else
#define ASSERT(R)
#endif

// do not move index
int ei_print_next_term(const char* prefix, const char* buf, int* pindex)
{
    int saved_index = *pindex;
    int res;
    fprintf(stderr, prefix);
    res = ei_print_term(stderr, buf, pindex);
    fprintf(stderr, "\n");
    *pindex = saved_index;
    if ( res>=0 ) return 0;
    return res;
}

int ei_print_next2_terms(const char* prefix, const char* buf, int* pindex)
{
    int saved_index = *pindex;
    int res;
    fprintf(stderr, prefix);
    res = ei_print_term(stderr, buf, pindex);
    fprintf(stderr, "\n");
    if ( res < 0 )
    {
        *pindex = saved_index;
        return res;
    }
    res = ei_print_term(stderr, buf, pindex);
    fprintf(stderr, "\n");
    *pindex = saved_index;
    if ( res >= 0 ) return 0;
    return res;
}

